/**
 * Anderground project - Subway maps processor application.
 * Copyright (C) 2008-2009 Eldar Abusalimov, Ilya Shurigyn
 * 
 * This file is part of Anderground.
 * 
 * Anderground is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * Anderground is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Anderground.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.anderground.modules.drawer.dynamic;

import static org.anderground.modules.drawer.dynamic.Config.hubBackRadius;
import static org.anderground.modules.drawer.dynamic.Config.hubRadius;

import java.util.ArrayList;

import org.anderground.core.drawer.Calculator;
import org.anderground.core.graphics.Canvas;
import org.anderground.core.graphics.Color;
import org.anderground.core.graphics.PointF;
import org.anderground.core.graphics.RadialGradient;
import org.anderground.core.graphics.RectF;
import org.anderground.core.model.Station;

/**
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 */
class CompoundAmoeba extends Amoeba implements
		Comparable<CompoundAmoeba> {

	/** child amoebas */
	private Amoeba leftAmoeba, rightAmoeba;

	private PointF distantCoordF;

	private float distance;

	private static int instanceCounter;

	/**
	 * The secondary sign used at comparison of amoebas with identical distances
	 */
	private int instanceId = instanceCounter++;

	/**
	 * @param leftAmoeba
	 * @param rightAmoeba
	 */
	public CompoundAmoeba(Amoeba leftAmoeba, Amoeba rightAmoeba) {
		this.leftAmoeba = leftAmoeba;
		this.rightAmoeba = rightAmoeba;
		// TODO
		assert (leftAmoeba.crossing == rightAmoeba.crossing);
		this.crossing = leftAmoeba.crossing;
		assert (leftAmoeba.parentAmoeba == null && rightAmoeba.parentAmoeba == null);
		leftAmoeba.parentAmoeba = this;
		rightAmoeba.parentAmoeba = this;
		leftAmoeba.brotherAmoeba = rightAmoeba;
		rightAmoeba.brotherAmoeba = leftAmoeba;

		this.size = leftAmoeba.size + rightAmoeba.size;

		this.stations = new Station[size];
		this.colors = new int[size];
		this.coords = new PointF[size];
		int k = 0;
		for (int i = 0; i < leftAmoeba.size; i++, k++) {
			stations[k] = leftAmoeba.stations[i];
			colors[k] = leftAmoeba.colors[i];
			coords[k] = leftAmoeba.coords[i];
		}
		for (int i = 0; i < rightAmoeba.size; i++, k++) {
			stations[k] = rightAmoeba.stations[i];
			colors[k] = rightAmoeba.colors[i];
			coords[k] = rightAmoeba.coords[i];
		}

		PointF coordF = PointF.averaged(leftAmoeba.coordF, rightAmoeba.coordF,
				leftAmoeba.size, rightAmoeba.size);

		float maxDistance = Float.NEGATIVE_INFINITY;
		float distance;
		for (PointF eachCoordF : this.coords) {
			distance = coordF.distanceTo(eachCoordF);
			if (distance > maxDistance) {
				maxDistance = distance;
				distantCoordF = eachCoordF;
			}
		}
		this.distance = maxDistance;

		this.coordF = coordF;
	}

	private PointF distantPointF = new PointF();

	private RectF arcRectF = new RectF();

	private float currentDistance;

	@Override
	protected void applyCalculator(Calculator calculator) {
		calculator.convert(distantCoordF, distantPointF);
		calculator.convert(coordF, pointF);
		currentDistance = pointF.distanceTo(distantPointF);
		if (currentDistance > Config.mergeDistance) {
			leftAmoeba.applyCalculator(calculator);
			rightAmoeba.applyCalculator(calculator);
		}
	}

	@Override
	protected void addDrawnAmoebas(ArrayList<Amoeba> drawnAmoebas) {
		if (currentDistance > Config.mergeDistance) {
			leftAmoeba.addDrawnAmoebas(drawnAmoebas);
			rightAmoeba.addDrawnAmoebas(drawnAmoebas);
		} else {
			drawnAmoebas.add(this);
		}
	}

	@Override
	protected void draw(Canvas canvas) {
		if (currentDistance > Config.mergeDistance) {
			leftAmoeba.draw(canvas);
			rightAmoeba.draw(canvas);

		} else {
			canvas.drawCircle(pointF, hubBackRadius, backComplexPaint);
			arcRectF.set(pointF.x - hubRadius, pointF.y - hubRadius, pointF.x
					+ hubRadius, pointF.y + hubRadius);
			float sector = 360 / size;
			float angle = 90;
			for (int color : colors) {
				complexPaint.setShader(new RadialGradient(pointF.x + 1,
						pointF.y + 1, hubBackRadius, Color.WHITE, color));
				canvas.drawArc(arcRectF, angle, sector, complexPaint);
				angle += sector;
			}

			this.drawLabels(canvas);
		}
	}

	@Override
	protected void highlight(Canvas canvas, int highlightColor) {
		if (currentDistance <= Config.mergeDistance) {
			lightComplexPaint.setColor(highlightColor);
			canvas.drawPoint(pointF, lightComplexPaint);
			draw(canvas);
		}
	}

	public float getCurrentDistance() {
		return currentDistance;
	}

	public int compareTo(CompoundAmoeba another) {
		if (this.distance == another.distance) {
			return (int) Math.signum(this.instanceId - another.instanceId);
		}
		return (int) Math.signum(this.distance - another.distance);
	}

}
